package com.example.spring5.IOC;

import com.example.spring5.bean.*;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * IOC解析
 * IoC（Inverse of Control:控制反转）是一种设计思想，
 *     就是将原本在程序中手动创建对象的控制权，交由Spring框架来管理。
 * IoC 目的：降低了组件之间的耦合性
 *         工厂模式也是为了降低代码的耦合性
 * IoC 在其他语言中也有应用，并非Spring特有。
 * IoC 容器是 Spring 用来实现 IoC 的载体，
 * IoC 容器实际上就是个Map（key，value）,Map 中存放的是各种对象。
 *      将对象之间的相互依赖关系交给 IoC 容器来管理，并由 IoC 容器完成对象的注入。
 *      这样可以很大程度上简化应用的开发，把应用从复杂的依赖关系中解放出来。
 * IoC 容器就像是一个工厂一样，当我们需要创建一个对象的时候，只需要配置好配置文件/注解即可，
 *      完全不用考虑对象是如何被创建出来的。
 *
 * 在实际项目中一个 Service 类可能有几百甚至上千个类作为它的底层，
 * 假如我们需要实例化这个Service，你可能要每次都要搞清这个Service 所有底层类的构造函数，
 * 这可能会把人逼疯。如果利用 IoC 的话，你只需要配置好，然后在需要的地方引用就行了，
 * 这大大增加了项目的可维护性且降低了开发难度。
 *
 * Spring 时代我们一般通过 XML 文件来配置 Bean，后来开发人员觉得 XML 文件来配置不太好，
 * 于是 SpringBoot 注解配置就慢慢开始流行起来。
 *
 * IOC：用到了xml解析，工厂模式，反射
 *
 * 第一、软件系统中由于引入了第三方IOC容器，生成对象的步骤变得有些复杂，
 *      本来是两者之间的事情，又凭空多出一道手续，
 *      所以，我们在刚开始使用IOC框架的时候，会感觉系统变得不太直观。
 *      所以，引入了一个全新的框架，就会增加团队成员学习和认识的培训成本，
 *      并且在以后的运行维护中，还得让新加入者具备同样的知识体系。
 * 第二、由于IOC容器生成对象是通过反射方式，在运行效率上有一定的损耗。
 *      如果你要追求运行效率的话，就必须对此进行权衡。
 * 第三、具体到IOC框架产品(比如：Spring)来讲，需要进行大量的配制工作，比较繁琐，
 *       对于一些小的项目而言，客观上也可能加大一些工作成本
 * 第四、IOC框架产品本身的成熟度需要进行评估，如果引入一个不成熟的IOC框架产品，
 *       那么会影响到整个项目，所以这也是一个隐性的风险
 *
 * 我们大体可以得出这样的结论：一些工作量不大的项目或者产品，不太适合使用IOC框架产品。
 * 另外，如果团队成员的知识能力欠缺，对于IOC框架产品缺乏深入的理解，也不要贸然引入。
 * 最后，特别强调运行效率的项目或者产品，也不太适合引入IOC框架产品，像WEB2.0网站就是这种情况。
 *
 */
public class IOC目的1 {
    public static void main(String[] args) {
        IOC创建对象的多种方式();
    }

    private static void IOC创建对象的多种方式() {
        UserDao u1 = new UserDao();
        u1.add();//一般方法   耦合性太高

        UserDao u2 = UserFactory.getDao1();
        u2.add();//工厂方法   降低了耦合性

        /**
         * 1、IOC 思想基于 IOC 容器完成，IOC 容器底层就是对象工厂
         * 2、Spring 提供 IOC 容器实现两种方式：（两个接口）
         *   （1）BeanFactory：IOC 容器基本实现，是 Spring 内部的使用接口，
         *            不提供开发人员进行使用
         *      加载配置文件时候不会创建对象，在获取对象（使用）才去创建对象
         *   （2）ApplicationContext：BeanFactory 接口的子接口，提供更多更强大的功能，
         *            一般由开发人员进行使用
         *      加载配置文件时候就会把在配置文件对象进行创建
         * 3、ApplicationContext 接口有实现类
         *      FileSystemXmlApplicationContext()  里面是全路径 也就是绝对路径
         *      ClassPathXmlApplicationContext()   里面是相对路径
         *
         * ctrl + h 查看此类的子类
         */
        ApplicationContext a = new ClassPathXmlApplicationContext("IOC.xml");
        UserDao user = a.getBean("userDao",UserDao.class);//默认是执行无参构造完成对象创建
        System.out.println(user);
        user.add();//IOC
    }
}



